package redis

import (
	"encoding/json"
	"fmt"
	"github.com/edgexfoundry/edgex-go/internal/app/models"
	pkgCommon "github.com/edgexfoundry/edgex-go/internal/pkg/common"
	"github.com/edgexfoundry/go-mod-core-contracts/v2/errors"
	"github.com/gomodule/redigo/redis"
)

const (
	ProductAttributeCollection          = "md|pa"
	ProductAttributeCollectionProductId = ProductAttributeCollection + DBKeySeparator + "productid"
	//ProductAttributeCollectionProductIdCode = ProductAttributeCollection + DBKeySeparator + "productid" + DBKeySeparator + "code"
)

func productAttributeStoreKey(id string) string {
	return CreateKey(ProductAttributeCollection, id)
}

// productAttributeIdExists 查询产品id是否存在
func productAttributeIdExists(conn redis.Conn, id string) (bool, errors.EdgeX) {
	exists, err := objectIdExists(conn, productAttributeStoreKey(id))
	if err != nil {
		return false, errors.NewCommonEdgeX(errors.KindDatabaseError, "product attribute existence check by id failed", err)
	}
	return exists, nil
}

// ProductAttributeById 通过id查询产品属性
func ProductAttributeById(conn redis.Conn, id string) (productAttribute models.ProductAttribute, edgeXerr errors.EdgeX) {
	edgeXerr = getObjectById(conn, productAttributeStoreKey(id), &productAttribute)
	if edgeXerr != nil {
		return productAttribute, errors.NewCommonEdgeXWrapper(edgeXerr)
	}
	return
}

// 查询产品code是否存在
//func productAttributeCodeExists(conn redis.Conn, code string) (bool, errors.EdgeX) {
//	exists, err := objectNameExists(conn, ProductAttributeCollectionCode, code)
//	if err != nil {
//		return false, errors.NewCommonEdgeX(errors.KindDatabaseError, "product attribute existence check by code failed", err)
//	}
//	return exists, nil
//}

// 向redis中存储产品属性
func sendAddProductAttributeCmd(conn redis.Conn, storeKey string, pa models.ProductAttribute) errors.EdgeX {
	dsJSONBytes, err := json.Marshal(pa)
	if err != nil {
		return errors.NewCommonEdgeX(errors.KindContractInvalid, "unable to JSON marshal product attribute for Redis persistence", err)
	}
	// md|pa:产品属性id     字符串
	_ = conn.Send(SET, storeKey, dsJSONBytes)
	// md|pa:productid:产品id     有序数组
	_ = conn.Send(ZADD, CreateKey(ProductAttributeCollectionProductId, pa.ProductId), 0, storeKey)
	//// md|pa:code     哈希
	//_ = conn.Send(HSET, ProductAttributeCollectionCode, pa.AttributeCode, storeKey)

	return nil
}

// 从redis中删除产品属性
func sendDeleteProductAttributeCmd(conn redis.Conn, storeKey string, pa models.ProductAttribute) errors.EdgeX {
	// md|pa:产品属性id     字符串
	_ = conn.Send(DEL, storeKey)
	// md|pa:productid:产品id     有序数组
	_ = conn.Send(ZREM, CreateKey(ProductAttributeCollectionProductId, pa.ProductId), storeKey)
	//// md|pa:code     哈希
	//_ = conn.Send(HDEL, ProductAttributeCollectionCode, pa.AttributeCode)
	return nil
}

// addProductAttribute 添加产品属性
func addProductAttribute(conn redis.Conn, pa models.ProductAttribute) (models.ProductAttribute, errors.EdgeX) {
	// 检查id是否存在
	exists, edgeXerr := productAttributeIdExists(conn, pa.Id)
	if edgeXerr != nil {
		return pa, errors.NewCommonEdgeXWrapper(edgeXerr)
	} else if exists {
		return pa, errors.NewCommonEdgeX(errors.KindDuplicateName, fmt.Sprintf("product attribute id %s already exists", pa.Id), edgeXerr)
	}

	// 检查属性的编码是否存在
	//exists, edgeXerr = productAttributeCodeExists(conn, pa.Code)
	//if edgeXerr != nil {
	//	return pa, errors.NewCommonEdgeXWrapper(edgeXerr)
	//} else if exists {
	//	return pa, errors.NewCommonEdgeX(errors.KindDuplicateName, fmt.Sprintf("product attribute code %s already exists", pa.AttributeCode), edgeXerr)
	//}

	ts := pkgCommon.MakeTimestamp()
	if pa.Created == 0 {
		pa.Created = ts
		pa.Modified = ts
	}

	storeKey := productAttributeStoreKey(pa.Id)
	_ = conn.Send(MULTI)
	edgeXerr = sendAddProductAttributeCmd(conn, storeKey, pa)
	if edgeXerr != nil {
		return pa, errors.NewCommonEdgeXWrapper(edgeXerr)
	}
	_, err := conn.Do(EXEC)
	if err != nil {
		errors.NewCommonEdgeX(errors.KindDatabaseError, "product attribute failed", err)
	}
	return pa, edgeXerr
}

// 通过产品id查询产品属性
func AttributesByProductId(conn redis.Conn, offset int, limit int, productId string) (productAttributes []models.ProductAttribute, edgeXerr errors.EdgeX) {
	// 根据productid创建有序数组的redis键
	// 分页查询该产品的属性
	objects, edgeXerr := getObjectsByRange(conn, CreateKey(ProductAttributeCollectionProductId, productId), offset, limit)
	if edgeXerr != nil {
		return productAttributes, errors.NewCommonEdgeXWrapper(edgeXerr)
	}
	// 将返回值转换为产品属性数组
	productAttributes = make([]models.ProductAttribute, len(objects))
	for i, in := range objects {
		pa := models.ProductAttribute{}
		err := json.Unmarshal(in, &pa)
		if err != nil {
			return []models.ProductAttribute{}, errors.NewCommonEdgeXWrapper(err)
		}
		productAttributes[i] = pa
	}
	return productAttributes, nil
}

// 批量删除产品属性
func ProductAttributeDelete(conn redis.Conn, productAttributeIds []string) errors.EdgeX {
	// 不能放到下面的事务里
	var productAttributes []models.ProductAttribute
	for _, id := range productAttributeIds {
		attributeById, err := ProductAttributeById(conn, id)
		if err != nil {
			return errors.NewCommonEdgeXWrapper(err)
		}
		productAttributes = append(productAttributes, attributeById)
	}

	// 事务开始
	_ = conn.Send(MULTI)

	for i, id := range productAttributeIds {
		storeKey := productAttributeStoreKey(id)
		err := sendDeleteProductAttributeCmd(conn, storeKey, productAttributes[i])
		if err != nil {
			return errors.NewCommonEdgeXWrapper(err)
		}
	}

	// 事务结束
	_, err := conn.Do(EXEC)
	if err != nil {
		return errors.NewCommonEdgeX(errors.KindDatabaseError, "product attribute delete failed", err)
	}
	return nil
}

func UpdateProductAttribute(conn redis.Conn, pa models.ProductAttribute) errors.EdgeX {
	// 通过id查询原产品属性
	oldAttribute, err := ProductAttributeById(conn, pa.Id)
	if err != nil {
		return errors.NewCommonEdgeXWrapper(err)
	}
	pa.Created = oldAttribute.Created
	ts := pkgCommon.MakeTimestamp()
	pa.Modified = ts

	// 检查属性的编码是否存在
	//if oldAttribute.AttributeCode != pa.AttributeCode {
	//	exists, err2 := productAttributeCodeExists(conn, pa.AttributeCode)
	//	if err2 != nil {
	//		return errors.NewCommonEdgeXWrapper(err2)
	//	} else if exists {
	//		return errors.NewCommonEdgeX(errors.KindDuplicateName, fmt.Sprintf("product attribute code %s already exists", pa.AttributeCode), err2)
	//	}
	//}

	// 事务开始
	_ = conn.Send(MULTI)
	storeKey := productAttributeStoreKey(pa.Id)
	sendDeleteProductAttributeCmd(conn, storeKey, oldAttribute)
	err = sendAddProductAttributeCmd(conn, storeKey, pa)
	if err != nil {
		return errors.NewCommonEdgeXWrapper(err)
	}
	// 事务结束
	_, err3 := conn.Do(EXEC)
	if err3 != nil {
		return errors.NewCommonEdgeXWrapper(err3)
	}
	return nil
}
